# -*- coding: utf-8 -*-

"""
Comment:

"""
import os

runs = np.arange(nRuns)

#Probabilities
probMNL_Segments = mnl(offerSets,prices,segQ,segments,segScale,segNP)                               #function based on multinomial logit
probMNL = np.dot(probMNL_Segments,segLambdas)
RS = np.sum(probMNL[:,:nProducts]*prices,1)  
Qt = np.sum(probMNL[:,:nProducts],1)  
effSets = efficientSets_largest_marginal_revenue_algorithm(Qt,RS,os2)    

#CDLP control and randomization of offer sets
[Ts,objVal_cdlp] = cdlp(offerSets,RS,capcon,cap,probMNL,nTimeperiods,products)                          #calculate timeslots from CDLP
OS_run_t = getRandomOSwithCDLP(nTimeperiods,nRuns,Ts,seed=1234)                                         #random OS with inversion method                    

#Customer Streams (randomSegments,randomQualityindices,randomNopurch) for BH and UH III
[rSeg,rQ,rNP] = getRandomstreams(products,segments,segLambdas,segQ,segScale,timeperiods,runs,1,segNP,seed=12345)    #random customer streams with Monte-Carlo similation
filename = 'Randomstreams3_'+ str(inst) + '_' + str(nEvalWSK) + 'xWSK.npz'
path = dictt + '/' + filename
if filename in os.listdir(dictt):
    a = np.load(path)
    rSeg2 = a['arr_0']
    rQ2 = a['arr_1']
    rNP2 = a['arr_2']
else:
    [rSeg2,rQ2,rNP2] = getRandomstreams(products,segments,segLambdas,segQ,segScale,timeperiods,runs,nEvalWSK,segNP,seed=nTimeperiods*(nProducts+1)*nRuns+1)
    np.savez(path,rSeg2,rQ2,rNP2)

if np.where(Ts!=0)[0].size>4:
    print('\n\nToo many offered offer sets for Matlab in this instance! Change instance parameters...')
else:
    #Arrays to save data
    overview = np.zeros((nRuns,nTimeperiods,4)) 
    tickets_sold = np.zeros((nSegments,nProducts,nRuns),dtype=np.int32)
    revenues_BH_run = np.zeros(nRuns)       #booking horizon
    revenues_UP_run = np.zeros(nRuns)       #upsell problem mit stinf
    revenues_RCS_run_eval = np.zeros((nRuns,nEvalWSK))
    revenues_UH_run_eval = np.zeros((nRuns,nEvalWSK))
    revenues_UH2_run_eval = np.zeros((nRuns,nEvalWSK))
    revenues_UH_run = np.zeros(nRuns)       #upsell horizon b-f first,then e-b
    revenues_RCS_run = np.zeros(nRuns) 
    revenues_RCS2_run = np.zeros(nRuns)
    revenues_optn = np.zeros(nRuns)
    revenues_UHbinom_run = np.zeros(nRuns)  #binomial upsell horizon
    revenues_WSK_run_eval = np.zeros((nRuns,nEvalWSK))
    revenues_UH_WSK_run = np.zeros(nRuns)   #upsell horizon mit Evaluationen
    revenues_UH_newEps_run_eval = np.zeros((nRuns,nEvalWSK))
    revenues_UH_newEps_run = np.zeros(nRuns) 
    up_overview_I = np.zeros((1,6))
    up_overview_II = np.zeros((1,6))
    up_overview_III = np.zeros((1,6))
    up_overview_IV = np.zeros((1,6))
    up_overview_V = np.zeros((1,6))
    cap_overview = np.zeros((nRuns,6,cap.shape[0]))
    deniedUp = np.zeros((nRuns,nProducts,5))
    checkcapconst = np.zeros((nRuns,1))
    np.random.seed(1992)
    randi = uniform.rvs(loc=0,scale=1,size=[nRuns,nTimeperiods,nEvalWSK])
    groups = np.zeros(nRuns) 
    ppp_and_group = np.zeros((nRuns,nTimeperiods,7))
    
    time_elapsed_cont = np.zeros(nRuns)
    time_elapsed_BI = np.zeros(nRuns)
    
    Name = str(inst) + '_stinf' + str(stinf) + '_' + bound + str(eps) + '_' + uphierar + \
    '_nyp' + str(nyp) + '_' + str(nEvalWSK) + 'xWSK' + mode # + '_newEpsEval'
    
    #Simulation 
    for runn in runs: 
        np.random.seed(999)
        #Booking Horizon
        reservationsInRun = np.zeros((nSegments,nProducts),dtype=np.int32)
        resCap = np.copy(cap).reshape(-1)
        for t in timeperiods[0:int(Tshare*nTimeperiods)]:
            os2 = offerSets[OS_run_t[t,runn].astype(int),:]
            seg = rSeg[t,runn]
            q = rQ[t,:,runn].reshape(-1)
            nopurch = rNP[t,runn]
            utilities = q - np.squeeze(prices[:])
            utilities[capcon @ resCap == 0] = -np.inf
            utilities[os2==0] = -np.inf
            if (seg >= 0) and np.any(utilities>nopurch):
                y = np.argmax(utilities)
                reservationsInRun[seg,y] += 1
                resCap -= capcon[y,:]
                overview[runn,t,:] = np.array([t,seg,y,OS_run_t[t,runn]])
            else:
                overview[runn,t,:] = np.array([t,seg,-10,OS_run_t[t,runn]])
        overview[runn,int(Tshare*nTimeperiods):nTimeperiods,:] = np.array([-100,-1000,-10,0])
        
        #Evaluate solution
        tickets_sold[:,:,runn] = reservationsInRun        
        revenues_BH_run[runn] = np.sum(np.squeeze(prices)*reservationsInRun)
        rem_cap = cap.transpose() - np.sum(reservationsInRun @ capcon,axis=0)
        cap_overview[runn,0,:] = rem_cap
        if runn%1000 == 0:
            print(runn,rem_cap)
        overviewx = np.copy(overview)
        
        if np.any(rem_cap[0]!=cap):
            if np.any(rem_cap[0][1:]>0):
                if stinf == 2: #standard method based on offer sets
                   prob,nns,values,uniqSeg,revenues_UP_run,revenues_UHbinom_run,time_elapsed_cont,checkcapconst = \
                   seen_odd_nonodd_products(timeperiods,segNP,mode,inst,revenues_UHbinom_run,bound,eps,checkcapconst,overview,capcon,runn,nRes, \
                                    rem_cap,nProducts,offerSets,prices,eng,segQ,segScale,cap,revenues_UP_run,time_elapsed_cont,uphierar,nyp,segLambdas)
                elif stinf == 6: #standard method based on offer sets
                    prob,nns,values,uniqSeg,revenues_UP_run,revenues_UHbinom_run,time_elapsed_cont,checkcapconst,timertime = \
                    offerset_based(segNP,mode,inst,revenues_UHbinom_run,bound,eps,checkcapconst,overview,capcon,runn,nRes,rem_cap,\
                                   nProducts,offerSets,prices,eng,segQ,segScale,cap,revenues_UP_run,time_elapsed_cont,uphierar,nyp,segLambdas)
                elif stinf == 9: #standard method based on offer sets
                    prob,nns,values,uniqSeg,revenues_UP_run,revenues_UHbinom_run,time_elapsed_cont,checkcapconst = \
                    seen_odd_nonodd_products_V2(timeperiods,segNP,mode,inst,revenues_UHbinom_run,bound,eps,checkcapconst,overview,capcon,runn,nRes,rem_cap,\
                                   nProducts,offerSets,prices,eng,segQ,segScale,cap,revenues_UP_run,time_elapsed_cont,uphierar,nyp,segLambdas)
                    
                if checkcapconst[runn] != -2:
                    #UPSELL HORIZON NUMBER I - first business-first, then eco-business
                    hi = []
                    for l in np.arange(values.shape[0]):
                        ll = int(values[l,0])
                        hi.append(tuple((values[l,0],values[l,1],(values[l,2] - prices[uniqSeg[ll,1]])[0],values[l,2],np.where(capcon[int(values[ll,1])]==1)[0][0],nns[ll])))
                    dtyp = [('Seg',int),('k',int),('revenue',float),('r_opt','float'),('compartment',int),('persons',float)]
                    arr = np.array(hi,dtyp)
                    hi2 = np.sort(arr,order=['compartment','revenue'])[::-1]
                    values2 = np.zeros((values.shape[0],values.shape[1]+2))
                    for l in np.arange(values.shape[0]):
                        for m in np.arange(values.shape[1]+2):
                            values2[l,m] = hi2[l][m]   
                            
                    all_cop_rem_cap = np.zeros((nEvalWSK,nRes))
                    if mode == '':
                        numb = 1
                    elif mode == '_p2':
                        numb = nEvalWSK
                    for ev in np.arange(numb):
                        uppies = [] 
                        no = -1
                        cop_rem_cap = np.copy(rem_cap)
                        for s in values2[:,0].astype(np.int):
                            no += 1
                            nprice = values[s,2]
                            nprices = np.copy(prices)
                            nprices[int(values2[no,1])] = nprice                            #replace price for upsell product
                            cust = np.where(np.all(overview[runn,:,1:4]==uniqSeg[s],axis=1))                 #get customers of segment
                            for c in cust[0]:
                                if mode == '':
                                    q = rQ[c,:,runn,ev]
                                elif mode == '_p2':
                                    q = rQ2[c,:,runn,ev]
                                utilities = q - np.squeeze(nprices)                         #calculate new utilitites with replaced price  
                                ut_prod = utilities[uniqSeg[s,1]]                           #get utility of product bought in BH 
                                y = q[int(values2[no,1])] - nprices[int(values2[no,1])]     #introduce/replace upsell product
                                yy = int(values2[no,1])
                                if y >= ut_prod and np.isin(y,utilities[capcon @ cop_rem_cap[0] == 0],invert=True):
                                    revenues_UH_run_eval[runn,ev] += nprice - prices[uniqSeg[s,1]] 
                                    cop_rem_cap[0] += capcon[uniqSeg[s,1],:] - capcon[yy,:]
                                    uppies.append(list((runn,c,uniqSeg[s,1],yy,s,nprice-prices[uniqSeg[s,1]][0])))
                                elif y >= ut_prod:
                                    deniedUp[runn,yy,0] += 1 
                        if len(uppies)!=0:
                            up_overview_I = np.vstack((up_overview_I,np.array(uppies)))   
                        all_cop_rem_cap[ev] = cop_rem_cap[0]
                    revenues_UH_run[runn] = np.mean(revenues_UH_run_eval[runn,np.arange(numb)])
                    cap_overview[runn,1,:] = np.mean(all_cop_rem_cap,0)
                    
                    #UPSELL HORIZON BINOMIAL
                    if stinf != 6 or (stinf == 6 and mode=='_p2'): 
                        offerSets2 = np.copy(offerSets)
                        lista = list()
                        for i in np.arange(uniqSeg.shape[0]):
                            vecmask = np.all(np.array([overview[runn,:,1:4]])==uniqSeg[i],2)
                            lista.append((timeperiods[vecmask[0]]))
                        cop_rem_cap = np.copy(rem_cap)
                        #Segments according to full information
                        uniqS, counts = np.unique(overviewx[runn,:,1:4],return_counts=True,axis=0)
                        uniqSegx = uniqS[uniqS[:,1]!=-10].astype(int)                                         #delete nopurch rows
                        counts2x = counts[uniqS[:,1]!=-10] 
                        counts2x = counts2x[np.isin(uniqSegx[:,1],np.where(capcon[:,nRes-1]==1),invert=True)]
                        uniqSegx = uniqSegx[np.isin(uniqSegx[:,1],np.where(capcon[:,nRes-1]==1),invert=True)]   #delete those in highest compartment
                        if  cop_rem_cap[0][1:][-1] == 0:
                            counts2x = counts2x[np.isin(uniqSegx[:,1],np.where(capcon[:,nRes-2]==1),invert=True)]
                            uniqSegx = uniqSegx[np.isin(uniqSegx[:,1],np.where(capcon[:,nRes-2]==1),invert=True)]   #delete those in highest compartment
                        #match lista to different segments
                        values3 = np.zeros([uniqSegx.shape[0],6])
                        groups[runn] = uniqSegx.shape[0]
                        for i in np.arange(uniqSegx.shape[0]):
                            vecmask = np.all(np.array([overviewx[runn,:,1:4]])==uniqSegx[i],2)
                            kunden = timeperiods[vecmask[0]]
                            ll = 0
                            for li in lista:
                                if kunden[0] in li:
                                    values3[i,0:3] = values2[values2[:,0]==ll,0:3]
                                    values3[i,3] = values2[values2[:,0]==ll,4]
                                    values3[i,5] = counts2x[i]
                                    ppp_and_group[runn,kunden,0] = values2[values2[:,0]==ll,2]
                                    ppp_and_group[runn,kunden,1:4] = uniqSeg[ll]
                                    ppp_and_group[runn,kunden,4:7] = uniqSegx[i]
                                    j = uniqSegx[i,1]
                                    k = values3[i,1].astype(int)
                                    l = uniqSegx[i,0]
                                    offerSets2 = np.copy(offerSets)
                                    ofs = offerSets2[uniqSegx[i,2],:]
                                    ofs2 = np.copy(ofs)
                                    ofs2[k] = 0
                                    values3[i,4] = max(0,1 - ((e**(segNP[0,l])+np.sum(ofs*e**(1/segScale[l]*(segQ[:,l]-np.squeeze(prices)))))/(e**(segNP[0,l])+e**(1/segScale[l]*(segQ[k,l]-values2[values2[:,0]==ll,3]))+np.sum(ofs2*e**(1/segScale[l]*(segQ[:,l]-np.squeeze(prices)))))))
                                ll += 1
                    else:
                        time_elapsed_BI[runn] = timertime
                        for i in np.arange(uniqSeg.shape[0]):
                            vecmask = np.all(np.array([overviewx[runn,:,1:4]])==uniqSeg[i],2)
                            kunden = timeperiods[vecmask[0]]
                            ppp_and_group[runn,kunden,0] = values2[values2[:,0]==i,2]
                            ppp_and_group[runn,kunden,1:4] = uniqSeg[i]
                            ppp_and_group[runn,kunden,4:7] = uniqSeg[i]
                            
                    #generate new customer segments
                    ppp_and_group2 = np.copy(ppp_and_group)
                    ppp_and_group2[runn,:,3] = ppp_and_group2[runn,:,0]+np.squeeze(prices[(ppp_and_group[runn,:,2]).astype(int)])
                    ppp_and_group2[runn,:,0:3] = ppp_and_group2[runn,:,4:7]
                    ppp_and_group2 = ppp_and_group2[runn,:,0:4]
                    uniqS, counts = np.unique(ppp_and_group2[:,:],return_counts=True,axis=0)
                    uniqSeg = uniqS[1:]
                    counts2 = counts[1:] 
                    if  rem_cap[0][1:][-1] == 0:
                        counts2 = counts2[np.isin(uniqSeg[:,1],np.where(capcon[:,nRes-2]==1),invert=True)]
                        uniqSeg = uniqSeg[np.isin(uniqSeg[:,1],np.where(capcon[:,nRes-2]==1),invert=True)]   #delete those in highest compartment
                    
                    [uplist,klist,p_comp,uplist_M,y_M] = calc_upsellpossibilities(uphierar,uniqSeg,counts2,nProducts,nRes,offerSets,prices,capcon,rem_cap)
                        
                    #save arrays to load into matlab     
                    scipy.io.savemat('data_nopt.mat',{'inst':inst,'segNP':segNP,'nyp':nyp,'bound':bound,'eps':eps,'Y':y_M,'upMat':uplist_M,\
                                                   'os':offerSets,'uniqSeg':uniqSeg,'prices':prices,'segQ':segQ,'capcon':capcon,\
                                                   'segScale':segScale,'cap':cap,'rem_cap':rem_cap,'cap':cap})
                    revenues_optn[runn] =  eng.nopt(nargout=1)
                else:
                    revenues_UP_run[runn] = -1000
                    revenues_RCS_run[runn] = -1000
                    revenues_RCS2_run[runn] = -1000
                    revenues_UH_WSK_run[runn] = -1000
                    revenues_UHbinom_run[runn] = -1000
                    revenues_UH_run[runn] = -1000
                    revenues_UH_newEps_run[runn] = -1000                    
            else:
                cap_overview[runn,1:4,:] = rem_cap
                revenues_UP_run[runn] = -1000
                revenues_RCS_run[runn] = -1000
                revenues_RCS2_run[runn] = -1000
                revenues_UH_WSK_run[runn] = -1000
                revenues_UHbinom_run[runn] = -1000
                revenues_UH_run[runn] = -1000
                revenues_UH_newEps_run[runn] = -1000
        else:
            cap_overview[runn,1:4,:] = rem_cap
            revenues_UP_run[runn] = -1000
            revenues_RCS_run[runn] = -1000
            revenues_RCS2_run[runn] = -1000
            revenues_UH_WSK_run[runn] = -1000
            revenues_UHbinom_run[runn] = -1000
            revenues_UH_run[runn] = -1000
            revenues_UH_newEps_run[runn] = -1000
            
    up_overview_I = up_overview_I[1:]           #delete initialising row
    up_overview_II = up_overview_II[1:]
